# -*- coding: utf-8 -*-
import os
import hashlib
from datetime import timedelta
from typing import Optional
from minio import Minio
from minio.error import S3Error
from fastapi import UploadFile

from configs.kb_config import MINIO_URL, MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MINIO_BUCKET_NAME


class MinioRepository:
    """Minio文件存储服务"""
    
    def __init__(self):
        self.client = Minio(
            MINIO_URL,
            access_key=MINIO_ACCESS_KEY,
            secret_key=MINIO_SECRET_KEY,
            secure=False  # 如果是https则设为True
        )
        self.bucket_name = MINIO_BUCKET_NAME
        self._ensure_bucket_exists()
    
    def _ensure_bucket_exists(self):
        """确保bucket存在"""
        try:
            if not self.client.bucket_exists(self.bucket_name):
                self.client.make_bucket(self.bucket_name)
        except S3Error as e:
            print(f"创建bucket失败: {e}")
    
    async def upload_file(self, file: UploadFile, object_name: str) -> bool:
        """
        上传文件到minio
        :param file: 上传的文件
        :param object_name: 对象名称（文件路径）
        :return: 是否上传成功
        """
        try:
            # 重置文件指针
            await file.seek(0)
            
            # 上传文件
            result = self.client.put_object(
                bucket_name=self.bucket_name,
                object_name=object_name,
                data=file.file,
                length=file.size,
                content_type=file.content_type
            )
            
            return True
        except S3Error as e:
            print(f"上传文件失败: {e}")
            return False
        except Exception as e:
            print(f"上传文件异常: {e}")
            return False
    
    def download_file(self, object_name: str, local_path: str) -> bool:
        """
        从minio下载文件
        :param object_name: 对象名称
        :param local_path: 本地保存路径
        :return: 是否下载成功
        """
        try:
            # 确保目录存在
            os.makedirs(os.path.dirname(local_path), exist_ok=True)
            
            # 下载文件
            self.client.fget_object(
                bucket_name=self.bucket_name,
                object_name=object_name,
                file_path=local_path
            )
            
            return True
        except S3Error as e:
            print(f"下载文件失败: {e}")
            return False
        except Exception as e:
            print(f"下载文件异常: {e}")
            return False
    
    def delete_file(self, object_name: str) -> bool:
        """
        删除minio中的文件
        :param object_name: 对象名称
        :return: 是否删除成功
        """
        try:
            self.client.remove_object(
                bucket_name=self.bucket_name,
                object_name=object_name
            )
            return True
        except S3Error as e:
            print(f"删除文件失败: {e}")
            return False
        except Exception as e:
            print(f"删除文件异常: {e}")
            return False
    
    def get_file_url(self, object_name: str, hours: int = 1) -> Optional[str]:
        """
        获取文件的预签名URL
        :param object_name: 对象名称
        :param hours: 过期时间（时）
        :return: 预签名URL
        """
        try:
            url = self.client.presigned_get_object(
                bucket_name=self.bucket_name,
                object_name=object_name,
                expires=timedelta(hours=hours)
            )
            return url
        except S3Error as e:
            print(f"获取文件URL失败: {e}")
            return None
        except Exception as e:
            print(f"获取文件URL异常: {e}")
            return None
    
    def file_exists(self, object_name: str) -> bool:
        """
        检查文件是否存在
        :param object_name: 对象名称
        :return: 文件是否存在
        """
        try:
            self.client.stat_object(
                bucket_name=self.bucket_name,
                object_name=object_name
            )
            return True
        except S3Error:
            return False
        except Exception as e:
            print(f"检查文件存在性异常: {e}")
            return False


# 创建全局minio服务实例
minio_service = MinioRepository()


def calculate_file_hash(file_content: bytes) -> str:
    """
    计算文件内容的SHA256哈希值
    :param file_content: 文件内容
    :return: SHA256哈希值
    """
    return hashlib.sha256(file_content).hexdigest()


async def get_file_hash(file: UploadFile) -> str:
    """
    获取上传文件的SHA256哈希值
    :param file: 上传的文件
    :return: SHA256哈希值
    """
    # 重置文件指针
    await file.seek(0)
    
    # 读取文件内容
    content = await file.read()
    
    # 计算哈希值
    return calculate_file_hash(content)
